﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Xml.Serialization;

namespace nGSO
{
    public delegate double ObjectiveFunction(Agent agent, double[] loc);

    [XmlRoot("agent")]
    public class Agent
    {
        #region Current Agent Algorithm Values
        [XmlIgnore]
        public IList<Agent> Neighbors
        {
            get
            {
                return History.Last().Neighbours;
            }
            set
            {
                History.Last().Neighbours = value;
            }
        }

        [XmlArrayItem("loc")]
        public double[] Loc 
        {
            get
            {
                return History.Last().Loc;
            }
            set
            {
                History.Last().Loc = value;
            }
        }

        [XmlIgnore]
        public double NeighborhoodRange
        {
            get
            {
                return History.Last().NeighborhoodRange;
            }
            set
            {
                History.Last().NeighborhoodRange = value;
            }
        }
        
        [XmlAttribute("fun_val")]
        public double Fitness
        {
            get
            {
                return History.Last().FunctionValue;
            }
            set
            {
                History.Last().FunctionValue = value;
            }
        }
        #endregion
        [XmlIgnore]
        public double[] NextLoc { get; set; }
        [XmlIgnore]
        public double NextNeighborhoodRange { get; set; }
        [XmlIgnore]
        public double Luciferin 
        { 
            get
            {
                return History.Last().Luciferin;
            }
            set
            {
                History.Last().Luciferin = value;
            }
        }
        [XmlIgnore]
        public double MovingProbability
        {
            get
            {
                return History.Last().MovingProbability;
            }
            set
            {
                History.Last().MovingProbability = value;
            }
        }
            
        [XmlIgnore]
        //[XmlArray("changes")]
        public List<AgentHistory> History { get; set; }

        [XmlAttribute("id")]
        public Guid Id {get;set;}

        /// <summary>
        /// For serailization only
        /// </summary>
        public Agent()
        {
            History = new List<AgentHistory>();
            History.Add(new AgentHistory() { Step = 0 });    
            Id = Guid.NewGuid();
        }

        public override bool Equals(object obj)
        {
            Agent compareToAgent = (Agent)obj;
            return compareToAgent.Id == this.Id;
        }

        public override int GetHashCode()
        {
            return base.GetHashCode();
        }

    }

    public static class AgentExtensions
    {
        public static double GetDistanceTo(this Agent agent, Agent otherAgent, int dims)
        {
            return GetDistanceTo(agent, otherAgent.Loc, dims);
        }

        public static double GetDistanceTo(this Agent agent, double[] targetLoc, int dims)
        {
            double[] agentLoc = agent.Loc;

            return GetDistance(targetLoc, dims, agentLoc);
        }

        
        public static double GetDistanceTo(this Agent agent, double[] targetLoc, int dims, int iterationAt)
        {
            AgentHistory agentState = agent.History[iterationAt];

            return GetDistance(targetLoc, dims, agentState.Loc);
        }

        public static double GetDistance(double[] targetLoc, int dims, double[] agentLoc)
        {
            double[] tmpDist = new double[dims];
            double[] potentialNeighborLoc = targetLoc;

            double tmp = 0;
            for (int i = 0; i < dims; i++)
            {
                tmp += Math.Pow(agentLoc[i] - potentialNeighborLoc[i], 2);
            }
            double euclideanDistance = Math.Sqrt(tmp);

            return euclideanDistance;
        }

    }
}